home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / viewers / polyview / polyvw31.lha / Polyview3.1 / new / pvinfo.c < prev    next >
C/C++ Source or Header  |  1993-08-24  |  21KB  |  674 lines

  1. /*****************************************************************************
  2.  * NCSA Polyview 3.1                                                         *
  3.  *                                                                           *
  4.  * Version 3.1 changes and additions by Gilles Bourhis.                      *
  5.  * Version 3 changes and additions by Marc Andreessen.                       *
  6.  * Version 2 by Brian Calvert.                                               *
  7.  *                                                                           *
  8.  * Software Development Group                                                *
  9.  * National Center for Supercomputing Applications                           *
  10.  * University of Illinois at Urbana-Champaign                                *
  11.  *                                                                           *
  12.  * This is BETA release software.  As such it may contain software bugs and  *
  13.  * exhibit inconsistencies.                                                  *
  14.  *                                                                           *
  15.  * Please send bug reports to polyview@ncsa.uiuc.edu.                        *
  16.  *                                                                           *
  17.  * Copyright (c) 1992 The Board of Trustees of the University of Illinois.   *
  18.  *                                                                           *
  19.  * Permission to use, copy, and modify this software and its                 *
  20.  * documentation for educational, research, and non-profit purposes is       *
  21.  * hereby granted, provided that the above copyright notice, the original    *
  22.  * authors names, and this permission notice appear in all such copies.      *
  23.  * Any distribution of this software requires the explicit and written       *
  24.  * authorization of the authors.                                             *
  25.  *                                                                           *
  26.  * The University of Illinois makes no representations about the             *
  27.  * suitability of this software for any purpose.  It is provided "as is"     *
  28.  * without warranty of any kind.                                             *
  29.  *****************************************************************************/
  30.  
  31. /* $Id: pvinfo.c,v 1.2 93/08/24 10:29:53 gbourhis Exp $ */
  32.  
  33. #ifdef RCSLOG
  34. $Log:    pvinfo.c,v $
  35.  * Revision 1.2  93/08/24  10:29:53  gbourhis
  36.  * replace version string 3.0 by 3.1
  37.  * 
  38.  * Revision 1.1  92/09/18  10:55:26  marca
  39.  * Initial revision
  40.  * 
  41. #endif
  42.  
  43. #include "pv.h"
  44.  
  45. static window_t *info_win = NULL;
  46. static Widget info_base = NULL;
  47. static Widget info_text = NULL;
  48. static int info_is_posted = 0;
  49.  
  50. /* Number of items in our dialog box. */
  51. static int numitems;
  52.  
  53. static int itemval = 1;
  54.  
  55.  
  56.  
  57. /* ------------------------------------------------------------------------ */
  58. static int local_reset(state_t *state, window_t *win, void *w)
  59. {
  60.   return parse_line (state, "information reset", TRUE);
  61. }
  62.  
  63. /* ------------------------------------------------------------------------ */
  64. /* ------------------------- ConstructInfoString -------------------------- */
  65. /* ------------------------------------------------------------------------ */
  66.  
  67. #define STRCHUNK 100000
  68. #define ARBITRARY_LIMIT 300
  69. static int current_size = 0;
  70. static char *str = NULL;
  71.  
  72. static void local_strprintf(char * format, ...)
  73. {
  74.   va_list args;
  75.   char line[MAXLINELEN];
  76.   
  77.   va_start(args, format);
  78.  
  79.   /* Put string in line. */
  80.   vsprintf(line, format, args);
  81.  
  82.   /* Get more space if we think we need it. */
  83.   if (current_size - strlen(str) < 80)
  84.     {
  85.       current_size += STRCHUNK;
  86.       str = (char *)realloc (str, current_size * sizeof(char));
  87.       bzero (&(str[current_size - STRCHUNK]), STRCHUNK);
  88.     }
  89.  
  90.   /* Put line in info string. */
  91.   strcat (str, line);
  92.   strcat (str, "\n\0");
  93.   
  94.   va_end(args);
  95.  
  96.   return;
  97. }
  98.  
  99.  
  100. static int ConstructInfoString (state_t *state, window_t *win)
  101. {
  102.   window_t        *active;
  103.   object_t        *obj;
  104.   float            *pcoord;
  105.   long            k;
  106.   pickmode_t        pickmode;
  107.   float            scalar;
  108.  
  109.   /* Fetch the active window. */
  110.   active = win;
  111.  
  112.   /* Get the first item in the window. */
  113.   itemval = 1;
  114.   if ((active != NULL) && WinHasData(active))
  115.     {
  116.       /* Get the object and the element within it. */
  117.       obj = GetKthElementObj(WIN_CURROOTOBJ(active), itemval);
  118.       k = GetKthPickedElement(obj, itemval);
  119.       
  120.       /* Set the pickmode according to whatever was found. */
  121.       if ((obj == NULL) || (k == -1)) 
  122.         {
  123.           /* If nothing is currently selected, set the pickmode */
  124.           /* as if everything were selected. */
  125.           pickmode = PICK_ALL;
  126.           itemval = 1;
  127.           numitems = 1;
  128.         }
  129.       else 
  130.         {
  131.           pickmode = OBJ_PICKMODE(obj);
  132.         }
  133.     }
  134.   else
  135.     {
  136.       /* Clear out the window. */
  137.       XmxTextSetString (info_text, "No information.");
  138.     }
  139.  
  140.   /* Start up the string; we'll realloc in local_strprintf if
  141.      we need to. */
  142.   str = (char *)malloc (STRCHUNK * sizeof(char));
  143.   bzero (str, STRCHUNK);
  144.   current_size = STRCHUNK;
  145.   
  146.   /* Now actually fill in the panel with information according to */
  147.   /* the state of the system. */
  148.   if (active == NULL) 
  149.     {
  150.       /* No active window. */
  151.       local_strprintf
  152.         ("Active Window\n   %-6s %s\n   %-6s %s\n   %-6s %s\n   %-6s %s\n   %-6s %s\n   %-6s %s\n   %-6s %s\n", "Name", "<none>", 
  153.          "File", "<none>", 
  154.          "Frame", "<none>",
  155.          "X", "<none>",    
  156.          "Y", "<none>",    
  157.          "Z", "<none>",    
  158.          "Color", "<none>");
  159.     }
  160.   else if (WinHasNoData(active)) 
  161.     {
  162.       /* Active window contains no data. */
  163.       local_strprintf( "Active Window (no data)");
  164.       local_strprintf( "   %-6s %s", "Name",
  165.                        WIN_NAME(active));
  166.       local_strprintf( "   %-6s %s", "File",
  167.                        WIN_SOURCENAME(active));
  168.       local_strprintf( "   %-6s %s", "Frame",
  169.                        WIN_GROUPNAME(active));
  170.       local_strprintf( "   %-6s %s", "X",
  171.                        WIN_PXNAME(active));
  172.       local_strprintf( "   %-6s %s", "Y",
  173.                        WIN_PYNAME(active));
  174.       local_strprintf( "   %-6s %s", "Z",
  175.                        WIN_PZNAME(active));
  176.       local_strprintf( "   %-6s %s", "Color",
  177.                        WIN_VSCALARNAME(active));
  178.     }
  179.   else
  180.     {
  181.       switch (pickmode) 
  182.         {
  183.         case PICK_VERTEX:
  184.           for (itemval = 1; itemval <= numitems; itemval++)
  185.             {
  186.               /* Get the object and the element within it. */
  187.               obj = GetKthElementObj(WIN_CURROOTOBJ(active), itemval);
  188.               k = GetKthPickedElement(obj, itemval);
  189.               scalar = GetVertexScalar(state, obj, k);
  190.               pcoord = GetVertexCoord(state, obj, k);
  191.       
  192.               local_strprintf
  193.                 ( "Vertex %ld of %ld\n   %-6s %s\n   %-6s %-9s %.3e\n   %-6s (%.3f %.3f %.3f)",
  194.                   itemval, WIN_SELECTED(active), "Name",
  195.                   OBJ_NAME(obj),
  196.                   "Scalar", GetVdataName(obj, MVSCALAR), scalar,
  197.                   "Coord", pcoord[X], pcoord[Y], pcoord[Z]);
  198.  
  199.               if (itemval >= ARBITRARY_LIMIT)
  200.                 {
  201.                   local_strprintf("**** Exceeded reasonableness limit.\n**** Remaining primitives not reported.");
  202.                   goto done_vertices;
  203.                 }
  204.             }
  205.         done_vertices:
  206.           break;
  207.         case PICK_FACE:
  208.           for (itemval = 1; itemval <= numitems; itemval++)
  209.             {
  210.               /* Get the object and the element within it. */
  211.               obj = GetKthElementObj(WIN_CURROOTOBJ(active), itemval);
  212.               k = GetKthPickedElement(obj, itemval);
  213.               scalar = GetFaceScalar(state, obj, k);
  214.               pcoord = GetFaceCoord(state, obj, k);
  215.  
  216.               local_strprintf
  217.                 ( "Face %ld of %ld\n   %-6s %s\n   %-6s %-9s %.3e\n   %-6s (%.3f %.3f %.3f)",
  218.                   itemval, WIN_SELECTED(active),
  219.                   "Name",
  220.                   OBJ_NAME(obj),
  221.                   "Scalar", GetVdataName(obj, MVSCALAR), scalar,
  222.                   "Coord", pcoord[X], pcoord[Y], pcoord[Z]);
  223.               if (itemval >= ARBITRARY_LIMIT)
  224.                 {
  225.                   local_strprintf("**** Exceeded reasonableness limit.\n**** Remaining primitives not reported.");
  226.                   goto done_faces;
  227.                 }
  228.             }
  229.         done_faces:
  230.           break;
  231.         case PICK_OBJECT:
  232.           for (itemval = 1; itemval <= numitems; itemval++)
  233.             {
  234.               /* Get the object and the element within it. */
  235.               obj = GetKthElementObj(WIN_CURROOTOBJ(active), itemval);
  236.               k = GetKthPickedElement(obj, itemval);
  237.  
  238.               local_strprintf
  239.                 ( "Object %ld of %ld\n   %-6s %s\n   %-6s %ld\n   %-6s %ld\n   %-6s (%.3f %.3f %.3f)\n   %-6s (%.3f %.3f %.3f)\n   %-6s (%.3f %.3f %.3f)",
  240.                   itemval, WIN_SELECTED(active),
  241.                   "Name",
  242.                   OBJ_NAME(obj),
  243.                   "Verts",
  244.                   OBJ_STATS(obj,PX,0).rec_count,
  245.                   "Polys",
  246.                   OBJ_STATS(obj,MCONNECT,0).rec_count,
  247.                   "Min", OBJ_STATS(obj,PX,0).min,
  248.                   OBJ_STATS(obj,PY,0).min,
  249.                   OBJ_STATS(obj,PZ,0).min,
  250.                   "Mean", OBJ_STATS(obj,PX,0).mean,
  251.                   OBJ_STATS(obj,PY,0).mean,
  252.                   OBJ_STATS(obj,PZ,0).mean,
  253.                   "Max", OBJ_STATS(obj,PX,0).max,
  254.                   OBJ_STATS(obj,PY,0).max,
  255.                   OBJ_STATS(obj,PZ,0).max);
  256.               if (itemval >= ARBITRARY_LIMIT)
  257.                 {
  258.                   local_strprintf("**** Exceeded reasonableness limit.\n**** Remaining primitives not reported.");
  259.                   goto done_objects;
  260.                 }
  261.             }
  262.         done_objects:
  263.           break;
  264.         case PICK_NONE:
  265.         case PICK_ALL:
  266.           local_strprintf( "Active Window");
  267.           local_strprintf( "   %-6s %s", "Name",
  268.                            WIN_NAME(active));
  269.           local_strprintf( "   %-6s %s", "File",
  270.                            WIN_SOURCENAME(active));
  271.           local_strprintf( "   %-6s %s", "Frame",
  272.                            WIN_GROUPNAME(active));
  273.           local_strprintf( "   %-6s %s", "X",
  274.                            WIN_PXNAME(active));
  275.           local_strprintf( "   %-6s %s", "Y",
  276.                            WIN_PYNAME(active));
  277.           local_strprintf( "   %-6s %s", "Z",
  278.                            WIN_PZNAME(active));
  279.           local_strprintf( "   %-6s %s", "Color",
  280.                            WIN_VSCALARNAME(active));
  281.           break;
  282.         default:
  283.           local_strprintf( "<ERROR>");
  284.           break;          
  285.         }
  286.     }
  287.  
  288.   XmxTextSetString (info_text, str);
  289.   free (str);
  290.   str = NULL;
  291.   
  292.   return ST_OKAY;
  293. }
  294.  
  295. /* ------------------------------------------------------------------------ */
  296. int init_info_fn(state_t *state, window_t *win, int reset)
  297. {
  298.   return init_info (state, state->active_windows, win, reset);
  299. }
  300.  
  301. /* ------------------------------------------------------------------------ */
  302. /* palette and reset aren't used here, but what the hell. */
  303. int init_info(state_t *state, window_t *active, window_t *palette, int reset)
  304. {
  305.   if ((active == NULL) || (WIN_FRAMELIST(active) == NULL)) 
  306.     {
  307.       /* No active window or frame.  Empty the window. */
  308.       XmxTextSetString (info_text, "No information.");
  309.       numitems = 1;
  310.     }
  311.   else 
  312.     {
  313.       if ((WIN_CURROOTOBJ(active) != NULL) &&
  314.           (WIN_ROOTOBJINFO(active) != NULL)) 
  315.         {
  316.           /* Set the number of items in the goddamn text. */
  317.           numitems = WIN_SELECTED(active);
  318.         }
  319.     }
  320.  
  321.   if (active == palette)
  322.     active = state->active_windows;
  323.   ConstructInfoString (state, active);
  324.  
  325.   return ST_OKAY;
  326. }
  327.  
  328.  
  329. /* ------------------------------------------------------------------------ */
  330. char *GetVdataName(object_t *obj, int slot)
  331. {
  332.   Vdata_t *vdata;
  333.   char *name;
  334.   
  335.   /* Get a pointer to the vdata, if any. */
  336.   if (obj == NULL)
  337.     vdata = NULL;
  338.   else
  339.     vdata = OBJ_VDATA(obj, slot);
  340.   
  341.   if ((vdata == NULL) || (*VDA_NAME(vdata) == '\0')) 
  342.       name = "<none>";
  343.   else 
  344.       name = VDA_NAME(vdata);
  345.   
  346.   return name;
  347. }
  348.  
  349. /* ------------------------------------------------------------------------ */
  350. long GetKthPickedElement(object_t *obj, long k)
  351. {
  352.   long i;
  353.   char *picked;
  354.     
  355.   /* If the object is NULL, return a nonsense value. */
  356.   if (obj == NULL)
  357.     return -1;
  358.   
  359.   /* Find out how many picked elements to skip in the picked list. */
  360.   k -= OBJ_FIRSTID(obj);
  361.   picked = OBJ_PICKLIST(obj);
  362.   
  363.   if (picked == NULL)
  364.     return -1;
  365.  
  366.   assert (k >= 0);
  367.   
  368.   /* Search for the kth selected element. */
  369.   for (i = 0; k >= 0; i++, picked++)
  370.     if (*picked) 
  371.       {
  372.         k--;
  373.         if (k < 0)
  374.           break;
  375.       }
  376.   
  377.   /* Return the index of the element. */
  378.   return i;
  379. }
  380.  
  381. /* ------------------------------------------------------------------------ */
  382. float GetVertexScalar(state_t *state, object_t *obj, long k)
  383. {
  384.   float *scalar;
  385.   
  386.   /* Get a pointer to the object's vdata list. */
  387.   if ((scalar = (float *) get_data(state, OBJ_VDATA(obj, MVSCALAR))) ==
  388.       NULL) 
  389.     return 0.0;
  390.   else 
  391.     return scalar[k];
  392. }
  393.  
  394. /* ------------------------------------------------------------------------ */
  395. float *GetVertexCoord(state_t *state, object_t *obj, long k)
  396. {
  397.   float *pcoord;
  398.   
  399.   /* Get a pointer to the object's vdata list. */
  400.   if ((pcoord = (float *) get_data(state, OBJ_VDATA(obj, PCOORD))) == NULL)
  401.     return NULL;
  402.   else
  403.     return pcoord + DIMS*k;
  404. }
  405.  
  406. /* ------------------------------------------------------------------------ */
  407. int GetVertexColor(state_t *state, object_t *obj, long k)
  408. {
  409.   int *colorp;
  410.   
  411.   /* Get a pointer to the object's vdata list. */
  412.   if ((colorp = (int *) get_data(state, OBJ_VDATA(obj, VCOLOR))) == NULL)
  413.     return 0;
  414.   else
  415.     return colorp[k];
  416. }
  417.  
  418. /* ------------------------------------------------------------------------ */
  419. float GetFaceScalar(state_t *state, object_t *obj, long k)
  420. {
  421.   long *connect;
  422.   float *scalar;
  423.   long nvert;
  424.   float value;
  425.   long i, j;
  426.     
  427.   /* Get a pointer to the object's connectivity list. */
  428.   if (((connect = (long *) get_data(state, OBJ_VDATA(obj, MCONNECT))) 
  429.        == NULL) || 
  430.       ((scalar = (float *) get_data(state, OBJ_VDATA(obj, MVSCALAR))) 
  431.        == NULL)) 
  432.     return 0.0;
  433.   else 
  434.     {
  435.       /* Adjust the connect list pointer to point to the first */
  436.       /* vertex of the selected polygon. */
  437.       value = 0.0;
  438.       connect += k * OBJ_STATS(obj, MCONNECT, 0).rec_size;
  439.       for (i = VDA_STATS(OBJ_VDATA(obj, MCONNECT)).rec_size, j = 0;
  440.            i > 0; i--, j++, connect++) 
  441.         {
  442.           if (*connect == 0)
  443.             break;
  444.           else 
  445.             value += scalar[*connect - 1];
  446.         }
  447.       
  448.       return value / j;
  449.     }
  450. }
  451.  
  452. /* ------------------------------------------------------------------------ */
  453. float *GetFaceCoord(state_t *state, object_t *obj, long k)
  454. {
  455.   long *connect;
  456.   float *pcoord;
  457.   static float center[DIMS];
  458.   long nvert;
  459.   long i, j;
  460.   
  461.   /* Get a pointer to the object's connectivity list. */
  462.   if (((connect = 
  463.         (long *) get_data(state, OBJ_VDATA(obj, MCONNECT))) == NULL) ||
  464.       ((pcoord = (float *) get_data(state, OBJ_VDATA(obj, PCOORD))) == NULL))
  465.     {
  466.       return NULL;
  467.     }
  468.   else 
  469.     {
  470.       /* Adjust the connect list pointer to point to the first */
  471.       /* vertex of the selected polygon. */
  472.       center[X] = center[Y] = center[Z] = 0.0;
  473.       connect += k * OBJ_STATS(obj, MCONNECT, 0).rec_size;
  474.       for (i = VDA_STATS(OBJ_VDATA(obj, MCONNECT)).rec_size, j = 0;
  475.            i > 0; i--, j++, connect++) 
  476.         {
  477.           if (*connect == 0)
  478.             break;
  479.           else 
  480.             {
  481.               center[X] += pcoord[X + DIMS*(*connect - 1)];
  482.               center[Y] += pcoord[Y + DIMS*(*connect - 1)];
  483.               center[Z] += pcoord[Z + DIMS*(*connect - 1)];
  484.             }
  485.         }
  486.       
  487.       /* Average the coordinates. */
  488.       center[X] /= j;
  489.       center[Y] /= j;
  490.       center[Z] /= j;
  491.       
  492.       return center;
  493.     }
  494. }
  495.  
  496.  
  497. /* ------------------------------------------------------------------------ */
  498. /* Returns a pointer to the object containing the kth selected element in */
  499. /* the sub-tree defined by "root".  Returns NULL if no such node. */
  500. object_t *GetKthElementObj(object_t *root, int k)
  501. {
  502.   object_t *prev, *curr;
  503.     
  504.   /* If k == 0, there are no objects selected. Quit. */
  505.   if (k == 0)
  506.     return NULL;
  507.   
  508.   /* If the root is an atomic object, assume k is contained in it. */
  509.   if (OBJ_TYPE(root) == ATOM)
  510.     return root;
  511.   
  512.   /* Keep a pointer to the last node examined, in case we pass it. */
  513.   /* Keep passing siblings until we either find the proper object */
  514.   /* or run out of objects. */
  515.   for (prev = NULL, curr = OBJ_CHILD(root); curr;
  516.        prev = curr, curr = OBJ_SIBLING(curr)) 
  517.     {
  518.       if (k < OBJ_FIRSTID(curr))
  519.         break;
  520.     }
  521.   
  522.   /* prev points to the object of interest.  If it is a composite, */
  523.   /* search its children.  Otherwise, return it. */
  524.   if (OBJ_TYPE(prev) == OBJECT)
  525.     return GetKthElementObj(prev, k);
  526.   else
  527.     return prev;
  528. }
  529.   
  530.  
  531.  
  532. /* ------------------------------------------------------------------------ */
  533. static XmxCallback (GUIinfoButtonCB)
  534. {
  535.   switch (XmxExtractToken ((int)client_data))
  536.     {
  537.     case PV_INFO_BUTTON_OK:
  538.       parse_line (gstate, "window close information", TRUE);
  539.       break;
  540.     case PV_INFO_BUTTON_HELP:
  541.       GUIdoHelp (PV_INFO_BUTTON_HELP);
  542.       break;
  543.     }
  544.   return;
  545. }
  546.  
  547. void destroy_info (state_t *state, window_t *window)
  548. {
  549.   XtUnmanageChild (info_base);
  550.   info_is_posted = 0;
  551.   return;
  552. }
  553.  
  554.  
  555. void create_info_dialog(state_t *state)
  556. {
  557.   Widget dialog_frame;
  558.   Widget info_form, buttons_form;
  559.   Widget dialog_sep;
  560.  
  561.   /* Create if necessary; definitely pop up. */
  562.  
  563.   if (info_base == NULL)
  564.     {
  565.       XmxSetUniqid (0);
  566.       
  567.       /* Create a new info window. */
  568.       info_base = XmxMakeFormDialog (state->base, "Polyview 3.1: Info Window");
  569.       
  570.       /* We put a frame inside the dialog form, then put a form
  571.          inside that. */
  572.       dialog_frame = XmxMakeFrame (info_base, XmxShadowOut);
  573.       
  574.       /* Constraints for base. */
  575.       XmxSetConstraints 
  576.         (dialog_frame, XmATTACH_FORM, XmATTACH_FORM, 
  577.          XmATTACH_FORM, XmATTACH_FORM,
  578.          NULL, NULL, NULL, NULL);
  579.       
  580.       /* Main form. */
  581.       info_form = XmxMakeForm (dialog_frame);
  582.       
  583.       /* Info window: text widget, not editable. */
  584.       XmxSetArg (XmNscrolledWindowMarginWidth, 10);
  585.       XmxSetArg (XmNscrolledWindowMarginHeight, 10);
  586.       XmxSetArg (XmNcursorPositionVisible, False);
  587.       XmxSetArg (XmNeditable, False);
  588.       XmxSetArg (XmNeditMode, XmMULTI_LINE_EDIT);
  589.       XmxSetArg (XmNrows, 15);
  590.       XmxSetArg (XmNcolumns, 50);
  591.       info_text = XmxMakeScrolledText (info_form);
  592.       
  593.       /* Load up initial text, by hand; don't use GUIsetInfo. */
  594.       /* XmxTextSetString (info_text, txt); */
  595.       
  596.       dialog_sep = XmxMakeHorizontalSeparator (info_form);
  597.       
  598.       buttons_form = XmxMakeFormAndTwoButtons
  599.         (info_form, GUIinfoButtonCB, "OK", "Help", PV_INFO_BUTTON_OK, 
  600.          PV_INFO_BUTTON_HELP);
  601.  
  602.       /* Constraints for info_form. */
  603.       /* XmxSetOffsets (XtParent (info_text), 10, 10, 10, 10); */
  604.       XmxSetConstraints 
  605.         (XtParent (info_text), XmATTACH_FORM, XmATTACH_WIDGET, 
  606.          XmATTACH_FORM, XmATTACH_FORM, NULL, dialog_sep, NULL, NULL);
  607.       XmxSetArg (XmNtopOffset, 10);
  608.       XmxSetConstraints 
  609.         (dialog_sep, XmATTACH_NONE, XmATTACH_WIDGET, XmATTACH_FORM, 
  610.          XmATTACH_FORM,
  611.          NULL, buttons_form, NULL, NULL);
  612.       XmxSetConstraints 
  613.         (buttons_form, XmATTACH_NONE, XmATTACH_FORM, XmATTACH_FORM, 
  614.          XmATTACH_FORM,
  615.          NULL, NULL, NULL, NULL);
  616.  
  617.       /* Add the window to the internal structs so we get messages. */
  618.       info_win = add_window (state, "info", DIALOG, 
  619.                              NULL /* init */, 
  620.                              NULL /* redraw */, 
  621.                              NULL /* animate */, 
  622.                              NULL /* event */,
  623.                              notify_info /* notify */, 
  624.                              NULL /* destroy */);
  625.     }
  626.  
  627.   /* Manage or remanage. */
  628.   XmxManageRemanage (info_base);
  629.   info_is_posted = 1;
  630.  
  631.   /* We do this instead of registering init_info as init function
  632.      in add_window above, because this works, and that doesn't. */
  633.   init_info_fn (state, info_win, 1);
  634.  
  635.   return;
  636. }
  637.  
  638.  
  639. int notify_info(state_t * state, window_t * send_win, window_t * recv_win,
  640.                 int message, va_list args)
  641. {
  642.   int status;
  643.   window_t *active;
  644.     
  645.   status = ST_OKAY;
  646.  
  647.   if (info_is_posted)
  648.     {
  649.       active = state->active_windows;
  650.       switch (message)
  651.         {
  652.         case MSG_NEWACT: /* new active window only */
  653.           init_info(state, send_win, recv_win, TRUE);
  654.           break;
  655.         case MSG_NEWPICK:
  656.         case MSG_NEWFRAME:
  657.         case MSG_NEWDATA:
  658.           /* Only update the window if this is the current window. */
  659.           if (send_win == state->active_windows) 
  660.             init_info(state, send_win, recv_win, FALSE);
  661.           break;
  662.         case MSG_CLOSING:
  663.         case MSG_VIEWCHG:
  664.         case MSG_REDRAW:
  665.         default:
  666.           break;
  667.         }
  668.     }
  669.   
  670.   return status;
  671. }
  672.  
  673.  
  674.